package com.example.calculator;
import android.os.SystemClock;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.util.StringTokenizer;
public class MainActivity extends AppCompatActivity {
    private Button[] btn = new Button[10]; //0~9 十个按键
    private TextView display; //显示器,用于显示输出结果
    private Button div;
    private Button mul;
    private Button sub;
    private Button add;
    //除法运算按钮/
//乘法运算按钮*
//减法运算按钮-
//加法运算按钮+
    private Button equal; //等于号按钮=
    private Button dot;
    private Button del;
    private Button c;
    //小数点按钮.
//退格键按钮
//清除键按钮
    public String str_old; //保存原来的算式样子
    public boolean vbegin = true;
    public boolean tip_lock = true;
    //输入控制，true 为重新输入，false 为接着输入
//true 表示正确，可以继续输入；false 表示有误，输入被锁定
    public boolean equals_flag = true; //判断是否是按=之后的输入，true 表示输入在=之前，false 反之
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//获取界面元素
        display = (TextView)findViewById(R.id.TV_display);
        btn[0] = (Button)findViewById(R.id.Btn_0);
        btn[1] = (Button)findViewById(R.id.Btn_1);
        btn[2] = (Button)findViewById(R.id.Btn_2);
        btn[3] = (Button)findViewById(R.id.Btn_3);
        btn[4] = (Button)findViewById(R.id.Btn_4);
        btn[5] = (Button)findViewById(R.id.Btn_5);
        btn[6] = (Button)findViewById(R.id.Btn_6);
        btn[7] = (Button)findViewById(R.id.Btn_7);
        btn[8] = (Button)findViewById(R.id.Btn_8);
        btn[9] = (Button)findViewById(R.id.Btn_9);
        div = (Button)findViewById(R.id.Btn_division);
        mul = (Button)findViewById(R.id.Btn_multiply);
        sub = (Button)findViewById(R.id.Btn_subtract);
        add = (Button)findViewById(R.id.Btn_add);
        equal = (Button)findViewById(R.id.Btn_equal);
        del = (Button)findViewById(R.id.Btn_delete);
        dot = (Button)findViewById(R.id.Btn_dot);
        c = (Button)findViewById(R.id.Btn_cancel);
//为数字按键绑定监听器
        for(int i = 0; i < 10; ++i) {
            btn[i].setOnClickListener(actionPerformed);
        }
//为+-*/等按键绑定监听器
        div.setOnClickListener(actionPerformed);
        mul.setOnClickListener(actionPerformed);
        sub.setOnClickListener(actionPerformed);
        add.setOnClickListener(actionPerformed);
        equal.setOnClickListener(actionPerformed);
        del.setOnClickListener(actionPerformed);
        dot.setOnClickListener(actionPerformed);
        c.setOnClickListener(actionPerformed);
    }
    /*
    * 计时器按钮点击事件监听器，实现计算命令的捕捉
    */
    String[] Tipcommand = new String[500]; //计算命令缓存
    int tip_i = 0; //Tipcommand 的指针



    private View.OnClickListener actionPerformed = new View.OnClickListener() {
        public void onClick(View v) {
            String command = ((Button)v).getText().toString();
//按键上的命令获取
            String str = display.getText().toString();
//显示器上的字符串
//检测输入是否合法
            if(equals_flag == false && "0123456789.+-*/".indexOf(command) != -1) {
//检测显示器上的字符串是否合法
                if(right(str)) {
                    if("+-*/".indexOf(command) != -1) {
                        for(int i =0 ; i < str.length(); i++) {
                            Tipcommand[tip_i] = String.valueOf(str.charAt(i));
                            tip_i++;
                        }
                        vbegin = false;
                    }
                } else {
                    display.setText("0");
                    vbegin = true;
                    tip_i = 0;
                    tip_lock = true;
                }
                equals_flag = true;
            }
            if("0123456789.+-*/".indexOf(command) != -1 && tip_lock) {
                Tipcommand[tip_i] = command;
                tip_i++;
            }
//若输入正确，则将输入信息显示到显示器上
            if("0123456789.+-*/".indexOf(command) != -1 && tip_lock) {
                print(command);
            }//如果输入是退格键，并且是在按=之前
            else if(command.compareTo("Del") == 0 && equals_flag) {
//若之前输入的字符串合法则删除一个字符
                if(right(str)) {
                    if(str.length() > 1)
                        display.setText(str.substring(0, str.length() - 1));
                    else if(str.length() == 1) {
                        display.setText("0");
                        vbegin = true;
                        tip_i = 0;
                    }
                } //若之前输入的字符串不合法则删除全部字符
                else {



                    display.setText("0");
                    vbegin = true;
                    tip_i = 0;
                }
                if(display.getText().toString().compareTo("-") == 0 || equals_flag == false) {
                    display.setText("0");
                    vbegin = true;
                    tip_i = 0;
                }
                tip_lock = true;
                if(tip_i > 0)
                    tip_i--;
            } //如果是在按=之后输入退格键
            else if(command.compareTo("Del") == 0 && equals_flag ==false) {
                display.setText("0"); //将显示器内容设置为 0
                vbegin = true;
                tip_i = 0;
                tip_lock = true;
            } //如果输入的是清除键
            else if(command.compareTo("C") == 0) {
                display.setText("0");
                vbegin = true;
                tip_i = 0;
//将显示器内容设置为 0
//重新输入标志置为 true
//缓存命令位数清 0
//表明可以继续输入
//表明输入=之前
                tip_lock = true;
                equals_flag = true;
            }
//如果输入的是=号，并且输入合法
            else if(command.compareTo("=") == 0 && tip_lock && right(str) && equals_flag) {
                tip_i = 0;
                tip_lock = false;
                equals_flag = false;
                vbegin = true;
//表明不可以继续输入
//表明输入=之后
//重新输入标志设置 true
                new calc().process(str); //计算算式结果
            }
            tip_lock = true;
//表明可以继续输入
        }
    };
    /*
    * 向显示器 display 输出字符
    */
    private void print(String str) {
        if(vbegin) //清屏后输出



            display.setText(str);
        else //在屏幕原 str 后增添字符
            display.append(str);
        vbegin = false;
    }
    /*
    * 判断一个 str 是否是合法的，返回值为 true、false
    * 只包含 0123456789.+ - * /的是合法的 str，返回 true
    * 包含了除 0123456789.+ - * /以外的字符的 str 为非法的，返回 false
    */
    private boolean right(String str) {
        int i = 0;
        for(i = 0;i < str.length();i++) {
            if(str.charAt(i)!='0' && str.charAt(i)!='1' && str.charAt(i)!='2' &&
                    str.charAt(i)!='3' && str.charAt(i)!='4' && str.charAt(i)!='5' &&
                    str.charAt(i)!='6' && str.charAt(i)!='7' && str.charAt(i)!='8' &&
                    str.charAt(i)!='9' && str.charAt(i)!='.' && str.charAt(i)!='-' &&
                    str.charAt(i)!='+' && str.charAt(i)!='*' && str.charAt(i)!='/')
                break;
        }
        if(i == str.length()) {
            return true;
        } else {
            return false;
        }
    }
    /*
    * 整个计算核心，只要将表达式的整个字符串传入 calc().process()即可实现计算
    * 算法包括以下几部分：
    * 1、计算部分
    * 2、数据格式化
    * 3、错误提示

    process(String str)
    FP(double n)
    在查错无误的前提下完成计算
            使数据有相当的精确度
    showError(int code ,String str) 将错误返回 */
    public class calc {
        public calc(){ }
        final int MAXLEN = 500;
        /*
        * 计算表达式
        * 从左向右扫描，数字入 number 栈，运算符入 operator 栈
        * +-基本优先级为 1，×÷基本优先级为 2
        * 当前运算符优先级高于栈顶压栈，低于栈顶弹出一个运算符与两个数进行运算
        * 重复直到当前运算符大于栈顶



        * 扫描完后对剩下的运算符与数字依次计算
        */
        public void process(String str) {
            int topOp = 0;
            int topNum = 0;
            int flag = 1;
//作为 weight[]、operator[]的计数器；
//number[]的计数器
//作为正负数的计数器，1 为正数，-1 为负数
//临时记录优先级的变化
            int weightTemp = 0;
            int weight[];
//保存 operator 栈中运算符的优先级，以 topOp 计数
//保存数字，以 topNum 计数
            double number[];
            char ch, ch_gai, operator[]; //operator[]保存运算符，以 topOp 计数
            String num;
//记录数字，str 以+-*/分段，+-*/字符之间的字符串即为数字
            weight = new int[MAXLEN];
            number = new double[MAXLEN];
            operator = new char[MAXLEN];
            String expression = str;
            StringTokenizer expToken = new StringTokenizer(expression,"+-*/");
            int i = 0;
            while (i < expression.length()) {
                ch = expression.charAt(i);
//判断正负数
                if (i == 0) {
                    if (ch == '-')
                        flag = -1;
                } else if(expression.charAt(i-1) == '(' && ch == '-')
                    flag = -1;
//取得数字，并将正负符号转移给数字
                if (ch <= '9' && ch >= '0'|| ch == '.') {
                    num = expToken.nextToken();
                    ch_gai = ch;
//取得整个数字
                    while (i < expression.length() && (ch_gai <= '9' && ch_gai >= '0'|| ch_gai == '.'))
                    {
                        ch_gai = expression.charAt(i++);
                    }
//将指针退回之前的位置
                    if (i >= expression.length())
                        i-=1;
                    else
                        i-=2;
                    if (num.compareTo(".") == 0)
                        number[topNum++] = 0;
//将正负符号转移给数字
                    else {
                        number[topNum++] = Double.parseDouble(num)*flag;



                        flag = 1;
                    }
                }
//计算运算符的优先级
                if (ch == '-' && flag == 1 || ch == '+' || ch == '*'|| ch == '/') {
                    switch (ch) {
//+-的优先级最低，为 1
                        case '+':
                        case '-': weightTemp = 1; break;
//*/的优先级稍高，为 2
                        case '*':
                        case '/': weightTemp = 2; break;
                    }
//如果当前优先级大于堆栈顶部元素，则直接入栈
                    if (topOp == 0 || weight[topOp-1] < weightTemp) {
                        weight[topOp] = weightTemp;
                        operator[topOp] = ch;
                        topOp++;
//否则将堆栈中运算符逐个取出，直到当前堆栈顶部运算符的优先级小于当前运算符
                    }else {
                        while (topOp > 0 && weight[topOp-1] >= weightTemp) {
                            switch (operator[topOp-1]) {
//取出数字数组的相应元素进行运算
                                case '+':
                                    number[topNum-2]+=number[topNum-1];
                                    break;
                                case '-':
                                    number[topNum-2]-=number[topNum-1];
                                    break;
                                case '*':
                                    number[topNum-2]*=number[topNum-1];
                                    break;
//判断除数为 0 的情况
                                case '/':
                                    if (number[topNum-1] == 0) {
                                        showError(1,str_old);
                                        return;
                                    }
                                    number[topNum-2]/=number[topNum-1];
                                    break;
                            }
//继续取堆栈的下一个元素进行判断
                            topNum--;
                            topOp--;



                        }
//将运算符入堆栈
                        weight[topOp] = weightTemp;
                        operator[topOp] = ch;
                        topOp++;
                    }
                }
                i++;
            }
//依次取出堆栈的运算符进行运算
            while (topOp>0) {
//+-*直接将数组的后两位数取出运算
                switch (operator[topOp-1]) {
                    case '+':
                        number[topNum-2]+=number[topNum-1];
                        break;
                    case '-':
                        number[topNum-2]-=number[topNum-1];
                        break;
                    case '*':
                        number[topNum-2]*=number[topNum-1];
                        break;
//涉及到除法时要考虑除数不能为零的情况
                    case '/':
                        if (number[topNum-1] == 0) {
                            showError(1,str_old);
                            return;
                        }
                        number[topNum-2]/=number[topNum-1];
                        break;
                }
//取堆栈下一个元素计算
                topNum--;
                topOp--;
            }
//如果是数字太大，提示错误信息
            if(number[0] > 7.3E306) {
                showError(2,str_old);
                return;
            }
//输出最终结果
            display.setText(String.valueOf(FP(number[0])));
        }



        /*
        * FP = floating point 控制小数位数，精度为 13 位
        */
        public double FP(double n) {
            DecimalFormat format = new DecimalFormat("0.#############");
            return Double.parseDouble(format.format(n));
        }
        /*
        * 错误提示，按了"="之后，若计算式在 process()过程中，出现错误，则进行提示
        */
        public void showError(int code ,String str) {
            String message="";
            switch (code) {
                case 1:
                    message = "零不能作除数";
                    break;
                case 2:
                    message = "值太大了，超出范围";
            }
            display.setText("\""+str+"\""+": "+message);
        }
    }
}